package org.moca.db;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;

import org.moca.db.MocaDB.DatabaseHelper;
import org.moca.db.MocaDB.SoundSQLFormat;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import android.util.Log;

public class SoundProvider extends ContentProvider {

    private static final String TAG = "SoundProvider";
    
    private static final String SOUND_TABLE_NAME = "sounds";
    public static final String SOUND_BUCKET_NAME = "/sdcard/dcim/moca/";
    
    private static final int SOUNDS = 1;
    private static final int SOUND_ID = 2;
    
    private DatabaseHelper mOpenHelper;
    private static final UriMatcher sUriMatcher;
    private static HashMap<String,String> sSoundProjectionMap;
    
    @Override
    public boolean onCreate() {
        Log.i(TAG, "onCreate()");
        mOpenHelper = new DatabaseHelper(getContext());
        return true;
    }
        
    private String buildFilenameFromId(String soundId) {
    	return "/data/data/org.moca/files/sound_" + soundId;
    }
    
    private String buildFilenameFromUri(Uri uri) {
    	return buildFilenameFromId(uri.getPathSegments().get(1));
    }
    
    private boolean deleteFile(String soundId) {
    	String filename = buildFilenameFromId(soundId);
    	
    	File f = new File(filename);
    	boolean result = f.delete();
    	Log.i(TAG, "Deleting file for id " + soundId + " : " + filename + " " + (result ? "succeeded" : "failed"));
    	return result;
    }
    
    private boolean deleteFile(Uri uri) {
    	String filename = buildFilenameFromUri(uri);
    	
    	File f = new File(filename);
    	boolean result = f.delete();
    	Log.i(TAG, "Deleting file for " + uri + " : " + filename + " " + (result ? "succeeded" : "failed"));
    	return result;
    }
    
    
    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
        //String filename = SOUND_BUCKET_NAME + uri.getFragment();
        String filename = buildFilenameFromUri(uri);
        //String filename = "/data/data/org.moca/files/" + uri.getPathSegments().get(1);
        Log.i(TAG, "openFile() for filename: " + filename);
        File f = new File(filename);
       
        int m = ParcelFileDescriptor.MODE_READ_ONLY;
        if ("w".equals(mode)) {
                m = ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE;
        } else if("rw".equals(mode) || "rwt".equals(mode)) {
                m = ParcelFileDescriptor.MODE_READ_WRITE;
        }

        return ParcelFileDescriptor.open(f,m);
    }
    
    
    
    
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        Log.i(TAG, "query() uri="+uri.toString() + " projection=" + TextUtils.join(",",projection));
        
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(SOUND_TABLE_NAME);
        
        switch(sUriMatcher.match(uri)) {
        case SOUNDS:    
            break;
        case SOUND_ID:
            qb.appendWhere(SoundSQLFormat._ID + "=" + uri.getPathSegments().get(1));
            break;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        
        String orderBy;
        if(TextUtils.isEmpty(sortOrder)) {
            orderBy = SoundSQLFormat.DEFAULT_SORT_ORDER;
        } else {
            orderBy = sortOrder;
        }
        
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count = 0; 
        
        switch(sUriMatcher.match(uri)) {
        case SOUNDS:
            count = db.update(SOUND_TABLE_NAME, values, selection, selectionArgs);
            break;
            
        case SOUND_ID:
            String procedureId = uri.getPathSegments().get(1);
            count = db.update(SOUND_TABLE_NAME, values, SoundSQLFormat._ID + "=" + procedureId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""), selectionArgs);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        switch (sUriMatcher.match(uri)) {
        case SOUNDS:
            //count = db.delete(SOUND_TABLE_NAME, selection, selectionArgs);
            LinkedList<String> idList = new LinkedList<String>();
        	Cursor c = query(SoundSQLFormat.CONTENT_URI, new String[] { SoundSQLFormat._ID }, selection, selectionArgs, null);
        	if(c.moveToFirst()) {
        		while(!c.isAfterLast()) {
        			String id = c.getString(c.getColumnIndex(SoundSQLFormat._ID));
        			idList.add(id);
        			c.moveToNext();
        		}
        	}
        	c.deactivate();
        	
            count = db.delete(SOUND_TABLE_NAME, selection, selectionArgs);
            
            for(String id : idList) {
            	deleteFile(id);
            }
            break;
        case SOUND_ID:
            String soundId = uri.getPathSegments().get(1); 
            count = db.delete(SOUND_TABLE_NAME, SoundSQLFormat._ID + "=" + soundId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""), selectionArgs);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        if (sUriMatcher.match(uri) != SOUNDS) {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        
        ContentValues values;
        if(initialValues != null) {
            values = new ContentValues(initialValues);
        } else {
            values = new ContentValues();
        }
        
        Long now = Long.valueOf(System.currentTimeMillis());
        
        if(values.containsKey(SoundSQLFormat.CREATED_DATE) == false) {
            values.put(SoundSQLFormat.CREATED_DATE, now);
        }
        
        if(values.containsKey(SoundSQLFormat.MODIFIED_DATE) == false) {
            values.put(SoundSQLFormat.MODIFIED_DATE, now);
        }
        
        if(values.containsKey(SoundSQLFormat.SAVED_PROCEDURE_ID) == false) {
            values.put(SoundSQLFormat.SAVED_PROCEDURE_ID, "");
        }
        
        if(values.containsKey(SoundSQLFormat.FILE_URI) == false) {
            values.put(SoundSQLFormat.FILE_URI, "");
        }
        
//        if(values.containsKey(SoundSQLFormat.FILE_VALID) == false) {
//            values.put(SoundSQLFormat.FILE_VALID, false);
//        }
//        
//        if(values.containsKey(SoundSQLFormat.FILE_SIZE) == false) {
//            values.put(SoundSQLFormat.FILE_SIZE, 0);
//        }
        
        if(values.containsKey(SoundSQLFormat.UPLOAD_PROGRESS) == false) {
            values.put(SoundSQLFormat.UPLOAD_PROGRESS, 0);
        }
        
        if(values.containsKey(SoundSQLFormat.UPLOADED) == false) {
            values.put(SoundSQLFormat.UPLOADED, false);
        }
        
        if(values.containsKey(SoundSQLFormat.ELEMENT_ID) == false) {
            values.put(SoundSQLFormat.ELEMENT_ID, "");
        }
        
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        long rowId = db.insert(SOUND_TABLE_NAME, SoundSQLFormat.SAVED_PROCEDURE_ID, values);
        if(rowId > 0) {
            
            String filename = rowId + "";
            try {
                getContext().openFileOutput(filename, Context.MODE_PRIVATE).close();
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Couldn't make the file: " + e);
            } catch (IOException e) {
                Log.e(TAG, "Couldn't make the file: " + e);
            }
            String path = getContext().getFileStreamPath(filename).getAbsolutePath();
            Log.i(TAG, "File path is : " + path);
            Uri noteUri = ContentUris.withAppendedId(SoundSQLFormat.CONTENT_URI, rowId);
            getContext().getContentResolver().notifyChange(noteUri, null);
            return noteUri;
        }
        
        throw new SQLException("Failed to insert row into " + uri);
    }

    @Override
    public String getType(Uri uri) {
        Log.i(TAG, "getType(uri="+uri.toString()+")");
        switch(sUriMatcher.match(uri)) {
        case SOUNDS:
            return SoundSQLFormat.CONTENT_TYPE;
        case SOUND_ID:
            return SoundSQLFormat.CONTENT_ITEM_TYPE;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }
    
    public static void onCreateDatabase(SQLiteDatabase db) {
        Log.i(TAG, "Creating Sound Table");
        db.execSQL("CREATE TABLE " + SOUND_TABLE_NAME + " ("
                + SoundSQLFormat._ID + " INTEGER PRIMARY KEY,"
                + SoundSQLFormat.SAVED_PROCEDURE_ID + " TEXT,"
                + SoundSQLFormat.ELEMENT_ID + " TEXT,"
                + SoundSQLFormat.FILE_URI + " TEXT,"
//                + SoundSQLFormat.FILE_VALID + " INTEGER,"
//                + SoundSQLFormat.FILE_SIZE + " INTEGER,"
                + SoundSQLFormat.UPLOAD_PROGRESS + " INTEGER,"
                + SoundSQLFormat.UPLOADED + " INTEGER,"
                + SoundSQLFormat.CREATED_DATE + " INTEGER,"
                + SoundSQLFormat.MODIFIED_DATE + " INTEGER"
                + ");");
    }
    
    public static void onUpgradeDatabase(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                + newVersion);
        if (oldVersion == 1 && newVersion == 2) {
        	// Do nothing
        }
    }

    
    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(MocaDB.SOUND_AUTHORITY, "sounds", SOUNDS);
        sUriMatcher.addURI(MocaDB.SOUND_AUTHORITY, "sounds/#", SOUND_ID);
        
        sSoundProjectionMap = new HashMap<String, String>();
        sSoundProjectionMap.put(SoundSQLFormat._ID, SoundSQLFormat._ID);
        sSoundProjectionMap.put(SoundSQLFormat.ELEMENT_ID, SoundSQLFormat.ELEMENT_ID);
        sSoundProjectionMap.put(SoundSQLFormat.SAVED_PROCEDURE_ID, SoundSQLFormat.SAVED_PROCEDURE_ID);
        sSoundProjectionMap.put(SoundSQLFormat.FILE_URI, SoundSQLFormat.FILE_URI);
//        sSoundProjectionMap.put(SoundSQLFormat.FILE_VALID, SoundSQLFormat.FILE_VALID);
//        sSoundProjectionMap.put(SoundSQLFormat.FILE_SIZE, SoundSQLFormat.FILE_SIZE);
        sSoundProjectionMap.put(SoundSQLFormat.UPLOADED, SoundSQLFormat.UPLOADED);
        sSoundProjectionMap.put(SoundSQLFormat.UPLOAD_PROGRESS, SoundSQLFormat.UPLOAD_PROGRESS);
        sSoundProjectionMap.put(SoundSQLFormat.CREATED_DATE, SoundSQLFormat.CREATED_DATE);
        sSoundProjectionMap.put(SoundSQLFormat.MODIFIED_DATE, SoundSQLFormat.MODIFIED_DATE);
    }
    
}
